//
//  Copyright 2011  comphilip
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Debug = System.Diagnostics.Debug;

namespace Dict4Engkoo.Engkoo {
	internal class EngkooQueryResult {
		private JToken _engkooResult;
		private bool _hasResult;

		public EngkooQueryResult(string EngkooResult) {
			try {
				_engkooResult = JObject.Parse(EngkooResult);
				JToken root = _engkooResult["ROOT"];
				if (root != null)
					_engkooResult = root;
			} catch (JsonReaderException) {
				_engkooResult = null;
			}

			_hasResult = _engkooResult != null && _engkooResult["DEF"] != null;
		}

		public string Word {
			get {
				if (HasResult)
					return Uri.UnescapeDataString(_engkooResult["$INPUT"].Value<string>());

				return string.Empty;
			}
		}

		public IEnumerable<Infection> Infections {
			get {
				if (!HasResult)
					yield break;

				JToken infs = _engkooResult["INFS"];
				if (infs == null)
					yield break;

				JToken inf = infs["INF"];
				if (inf == null)
					yield break;

				JArray infArray = inf as JArray;
				if (infArray == null)
					yield return new Infection {
					Type = Uri.UnescapeDataString(inf["$T"].Value<string>()),
					Word = Uri.UnescapeDataString(inf["I-E"]["$"].Value<string>())
				};
				else
					foreach (var item in infArray) {
						yield return new Infection {
							Type = Uri.UnescapeDataString(item["$T"].Value<string>()),
							Word = Uri.UnescapeDataString(item["I-E"]["$"].Value<string>())
						};
					}
			}
		}

		public IEnumerable<Pronunciation> Pronunciations {
			get {
				if (!HasResult)
					yield break;
				JToken pros = _engkooResult["PROS"];
				if (pros == null)
					yield break;
				JToken pro = pros["PRO"];
				if (pro == null)
					yield break;

				JArray proArray = pro as JArray;
				if (proArray == null)
					yield return new Pronunciation {
						Lang = Uri.UnescapeDataString(pro["$L"].Value<string>()),
						PhoneticSymbol = Uri.UnescapeDataString(pro["$"].Value<string>())
					};
				else
					foreach (var item in proArray) {
						yield return new Pronunciation {
							Lang = Uri.UnescapeDataString(item["$L"].Value<string>()),
							PhoneticSymbol = Uri.UnescapeDataString(item["$"].Value<string>())
						};
					}
			}
		}

		public IEnumerable<Collocation> Collocations {
			get {
				if (!HasResult)
					yield break;
				JToken colls = _engkooResult["COLLS"];
				if (colls == null)
					yield break;
				JToken cs = colls["CS"];
				if (cs == null)
					yield break;
				JArray csArray = cs as JArray;
				if (csArray != null)
					foreach (var item in csArray)
						yield return new Collocation(item);
				else
					yield return new Collocation(cs);
			}
		}

		public IEnumerable<Define> Defines {
			get {
				JToken def = _engkooResult["DEF"];
				if (def == null)
					yield break;
				JArray pairDef = def as JArray;
				if (pairDef != null) {
					Debug.Assert(pairDef.Count == 2, "DEF length not equal to 2");
					JToken sen0 = pairDef[0]["SENS"];
					JToken sen1 = pairDef[1]["SENS"];
					JArray sens0 = sen0 as JArray;
					JArray sens1 = sen1 as JArray;
					int length0 = sens0 != null ? sens0.Count : 1;
					int length1 = sens1 != null ? sens1.Count : 1;
					int lengh = length0 > length1 ? length0 : length1;
					for (int i = 0; i < lengh; ++i) {
						JToken token0 = null, token1 = null;
						if (sens0 != null) {
							if (sens0.Count > i)
								token0 = sens0[i];
						} else if (i == 0)
							token0 = sen0;

						if (sens1 != null) {
							if (sens1.Count > i)
								token1 = sens1[i];
						} else if (i == 0)
							token1 = sen1;

						yield return new Define(token0, token1);
					}
				}
				yield break;
			}
		}

		public IEnumerable<KeyValuePair<string, string>> Phrases {
			get {
				if (!HasResult)
					yield break;
				JToken phrases = _engkooResult["PHRASES"];
				if (phrases == null)
					yield break;
				JToken ph = phrases["PH"];
				if (ph == null)
					yield break;
				JArray array = ph as JArray;
				if (array != null)
					foreach (var item in array) {
						JToken target = item["$T"];
						JToken trans = item["$"];
						if (target != null)
							yield return new KeyValuePair<string, string>(Uri.UnescapeDataString(target.Value<string>()),
										 trans != null ? Uri.UnescapeDataString(trans.Value<string>()) : string.Empty);
					}
				else {
					JToken target = ph["$T"];
					JToken trans = ph["$"];
					if (target != null)
						yield return new KeyValuePair<string, string>(Uri.UnescapeDataString(target.Value<string>()),
									 trans != null ? Uri.UnescapeDataString(trans.Value<string>()) : string.Empty);
				}
			}
		}

		public IEnumerable<KeyValuePair<string, string>> Sentences {
			get {
				KeyValuePair<string, string>[] empty = new KeyValuePair<string, string>[] {};
				if (!HasResult)
					return empty;
				JToken sens = _engkooResult["SENTS"];
				if (sens == null)
					return empty;
				JToken sen = sens["SEN"];
				if (sen == null)
					return empty;

				return (new Sentences(sen).GetSentences());
			}
		}

		public IEnumerable<Thesaurus> Thesauruses {
			get {
				if (!HasResult)
					yield break;
				JToken thes = _engkooResult["THES"];
				if (thes == null)
					yield break;
				JToken the = thes["THE"];
				if (the == null)
					yield break;
				JArray array = the as JArray;
				if (array != null)
					foreach (var item in array)
						yield return new Thesaurus(item);
				else
					yield return new Thesaurus(the);
			}
		}

		public bool HasResult {
			get { return _hasResult; }
		}
	}
}

